import java.net.*;
import java.io.*;
import javax.crypto.*;
import java.security.*;
  public class ClientModel
  {

	  //Choose a port outside of the range 1-1024 (but same as server):
	  static final int port = 3226;
      protected static InputStream instr;
      protected static OutputStream outstr;
      protected static ObjectInputStream in;
      protected static ObjectOutputStream out;
      protected static Socket socket;
	  public static void main( String [] args) throws IOException
	  {
		 try 
		 {
			  InetAddress addr =
			  		  InetAddress.getLocalHost();

			  System.out.println("Server address = " + addr);
			  socket = new Socket(addr, port);
			  System.out.println(" Connected to socket: " + socket);

			  // Use a ObjectInputStream on the socket's InputStream to read the
			  // string sent by the server
             try{
              out = new ObjectOutputStream(
                        socket.getOutputStream());
             }
             catch (IOException transferexcept){
                 throw new IOException();
             }
             System.out.println("Made I/O stuff");

         }
		  catch( Exception e) 
		  {
			  System.out.println(e);
			  e.printStackTrace();
		  }

	  }
      public ClientModel()
	  {
          try 
          {
			  InetAddress addr =
              InetAddress.getLocalHost();
              
			  System.out.println("Server address = " + addr);
			  socket = new Socket(addr, port);
			  System.out.println(" Connected to socket: " + socket);
              
			  // Use a ObjectInputStream on the socket's InputStream to read the
			  // string sent by the server

              try{
                  // generate keys, create objectoutputstream. Write key. 
                  // generate object input stream. Read key.
                  // Generate objectcipheroutputstream.
                  KeyPair mykeys = KeyPairGenerator.getInstance(Xipher.algo).genKeyPair();
                  PublicKey mypubkey = mykeys.getPublic();
                  //System.out.println("My pubkey = " + mypubkey);
                  PrivateKey myprivkey = mykeys.getPrivate();
                  outstr = socket.getOutputStream();
                  out = new ObjectOutputStream(outstr);
                  out.writeObject(mypubkey);
                  Cipher myDCipher = new Xipher().getDCipher(myprivkey);
                  InputStream instr = null;
                  try{
                      instr = socket.getInputStream();
                      in = new ObjectInputStream(instr);
                      //System.out.println("Input stream ready.");
                  }
                  catch(Exception iosock){
                      //System.out.println("Couldn't create inputStream.");
                  }
                  PublicKey theirpubkey = (PublicKey) in.readObject();
                  Cipher myCipher = new Xipher().getCipher(theirpubkey);
                  System.out.println("Received pubkey " + theirpubkey);
//For Debug
                     // System.out.println("Cipher " + myCipher);
                     // System.out.println("DCiphter " + myDCipher);
      
                  
                  out = new ObjectOutputStream(outstr);

                  CipherOutputStream coutstream = new CipherOutputStream(out , myCipher);


                  System.out.println("Made Outputstream. Making inputstream...");
                  in = new ObjectInputStream(instr);
                  CipherInputStream cin = new CipherInputStream(in, myDCipher);
                  System.out.println("Made input stream.");
              }
              catch (Exception transferexcept){
                  throw transferexcept;
              }
              System.out.println("Made I/O stuff");
            // Close socket when finished
          }
		  catch( Exception e) 
		  {
			  System.out.println(e);
			  e.printStackTrace();
		  }
          
	  }
      
      public Response getResponse(Request req){
          try{
          out.writeObject(req);
          Response toret = (Response) in.readObject();
          return toret;
          }
          catch(Exception inoutexcept){
              System.out.println("You were not able to access database.\n" + inoutexcept);
              return null;
          }
      }

      public static void writeString(String str){
          try{
              out.writeObject(str);
          }
          catch(Exception inoutexcept){
              System.out.println("You were not able to access database.\n" + inoutexcept);
          }
      }
  }
